Skip to content

refactor: split bootstrap to smaller files for better readability#518

Merged
steveiliop56 merged 3 commits into
mainfrom
refactor/bootstrap
Dec 17, 2025
Merged

refactor: split bootstrap to smaller files for better readability#518
steveiliop56 merged 3 commits into
mainfrom
refactor/bootstrap

Conversation

@steveiliop56
Copy link
Copy Markdown
Member

@steveiliop56 steveiliop56 commented Dec 13, 2025

Summary by CodeRabbit

  • Refactor
    • Restructured internal service initialization and routing architecture for improved code organization and maintainability. Services are now centralized and bootstrapped through a unified flow, with configuration state consolidated in an internal context container.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Dec 13, 2025

Walkthrough

The changes refactor the bootstrap architecture by removing public middleware/controller/service interfaces and consolidating service initialization into a centralized app.context container and app.initServices method. A new app.setupRouter method replaces scattered route configuration, while services are wired into a public Services struct for organized dependency management.

Changes

Cohort / File(s) Summary
Bootstrap Application Structure
internal/bootstrap/app_bootstrap.go
Restructures BootstrapApp by removing public interfaces (Controller, Middleware, Service), moving configuration/state fields into an internal app.context struct, and introducing a public Services field. Replaces ad-hoc service initialization and route setup with centralized app.initServices() and app.setupRouter() methods. Adjusts heartbeat/diagnostic behavior and database cleanup routines.
Service Initialization
internal/bootstrap/service_bootstrap.go
Introduces new Services struct and BootstrapApp.initServices() method that orchestrates instantiation and initialization of core application services (Database, LDAP, Docker, AccessControls, Auth, OAuthBroker) with proper error handling and optional LDAP fallback.
Router Configuration
internal/bootstrap/router_bootstrap.go
Introduces new router bootstrap component that builds and configures the Gin engine, initializes middlewares (context, UI, zerolog), applies trusted proxies, and mounts API routes via multiple controllers with centralized error handling.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client
    participant App as BootstrapApp
    participant InitSvc as initServices()
    participant DB as DatabaseService
    participant LDAP as LdapService
    participant Docker as DockerService
    participant AC as AccessControlService
    participant Auth as AuthService
    participant OAuth as OAuthBrokerService
    participant Router as setupRouter()
    participant Engine as Gin Engine

    Client->>App: NewBootstrapApp(config)
    Client->>App: Run()
    
    App->>InitSvc: call initServices()
    
    InitSvc->>DB: Create & Init
    DB-->>InitSvc: success
    
    InitSvc->>LDAP: Create & Init
    LDAP-->>InitSvc: (optional, tolerates failure)
    
    InitSvc->>Docker: Create & Init
    Docker-->>InitSvc: success
    
    InitSvc->>AC: Create with Docker & Init
    AC-->>InitSvc: success
    
    InitSvc->>Auth: Create with composite config
    Auth->>Docker: (dependency)
    Auth->>LDAP: (dependency)
    Auth->>DB: (dependency)
    Auth-->>InitSvc: initialized
    
    InitSvc->>OAuth: Create & Init
    OAuth-->>InitSvc: success
    
    InitSvc-->>App: Services struct
    
    App->>Router: call setupRouter()
    Router->>Engine: Configure middlewares
    Router->>Engine: Mount controllers
    Engine-->>Router: configured
    Router-->>App: Gin Engine
    
    App->>App: Start HTTP/Unix socket
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Structural changes to BootstrapApp: The core struct is substantially modified with new internal context container and Services field; requires careful review of all state movement and access pattern changes.
  • New centralized service initialization: The initServices() method introduces orchestration logic with multiple service dependencies and error handling paths; verify initialization order and fallback behavior (especially LDAP tolerance).
  • Router bootstrap extraction: New setupRouter() method consolidates middleware and controller mounting; ensure middleware initialization order and error propagation are correct.
  • Interface removal impact: Verify that removing Controller, Middleware, and Service interfaces doesn't break any remaining references or expectations in the codebase.
  • Integration testing: The new startup sequence flow involves multiple service interactions that may require validation across the bootstrap path.

Possibly related PRs

  • refactor: rework file structure #325: Performs the same large-scale bootstrap and services refactoring, affecting the same files and architectural concerns (app_bootstrap.go, service initialization, and controller wiring).

Poem

🐰 A rabbit hops through code so grand,
Where services now hand-in-hand,
With context deep and router clean,
The finest bootstrap ever seen!
No more interfaces to confound—
One sequence flow, so tightly bound. ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: refactoring bootstrap code into smaller files for improved readability, which aligns with the creation of service_bootstrap.go and router_bootstrap.go alongside changes to app_bootstrap.go.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/bootstrap

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented Dec 13, 2025

Codecov Report

❌ Patch coverage is 0% with 141 lines in your changes missing coverage. Please review.
✅ Project coverage is 23.37%. Comparing base (3961589) to head (7df6084).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
internal/bootstrap/router_bootstrap.go 0.00% 60 Missing ⚠️
internal/bootstrap/service_bootstrap.go 0.00% 52 Missing ⚠️
internal/bootstrap/app_bootstrap.go 0.00% 29 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #518      +/-   ##
==========================================
- Coverage   23.56%   23.37%   -0.19%     
==========================================
  Files          36       38       +2     
  Lines        2245     2263      +18     
==========================================
  Hits          529      529              
- Misses       1679     1697      +18     
  Partials       37       37              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
internal/bootstrap/app_bootstrap.go (2)

98-132: Missing assignment: configuredProviders not stored in app.context.

The configuredProviders slice is built and validated but never assigned to app.context.configuredProviders. This causes the issue flagged in routes_bootstrap.go where an empty slice will be passed to ContextController.

Add the assignment before calling setupRoutes():

 	if len(configuredProviders) == 0 {
 		return fmt.Errorf("no authentication providers configured")
 	}

+	app.context.configuredProviders = configuredProviders
+
 	// Setup routes
 	engine, err := app.setupRoutes()

226-238: gorm.G[model.Session] is undefined and will cause compilation failure.

The code uses gorm.G[T] syntax which is only available in gorm.io/gen package, but gorm.io/gen is not a dependency in go.mod (only gorm.io/gorm v1.31.1 is present). Additionally, no generated query code or gen setup exists in the codebase. Standard gorm.io/gorm does not export G.

Either add gorm.io/gen as a dependency and set up code generation, or replace gorm.G[model.Session](db) with standard GORM API like db.Model(&model.Session{}).

This affects lines 233 in app_bootstrap.go and multiple lines in auth_service.go.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3961589 and 5cad1f0.

📒 Files selected for processing (3)
  • internal/bootstrap/app_bootstrap.go (6 hunks)
  • internal/bootstrap/routes_boostrap.go (1 hunks)
  • internal/bootstrap/service_bootstrap.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
internal/bootstrap/service_bootstrap.go (8)
internal/service/access_controls_service.go (2)
  • AccessControlsService (29-32)
  • NewAccessControlsService (34-38)
internal/service/auth_service.go (3)
  • AuthService (39-47)
  • NewAuthService (49-57)
  • AuthServiceConfig (28-37)
internal/service/database_service.go (3)
  • DatabaseService (21-24)
  • NewDatabaseService (26-30)
  • DatabaseServiceConfig (17-19)
internal/service/docker_service.go (2)
  • DockerService (14-18)
  • NewDockerService (20-22)
internal/service/ldap_service.go (3)
  • LdapService (24-28)
  • NewLdapService (30-34)
  • LdapServiceConfig (15-22)
internal/service/oauth_broker_service.go (2)
  • OAuthBrokerService (21-24)
  • NewOAuthBrokerService (26-31)
internal/bootstrap/app_bootstrap.go (1)
  • BootstrapApp (23-36)
internal/config/config.go (1)
  • SessionCookieName (11-11)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (go)
🔇 Additional comments (10)
internal/bootstrap/routes_boostrap.go (3)

12-22: LGTM!

The Gin engine initialization with recovery middleware and trusted proxies configuration is correctly implemented with proper error handling.


24-55: LGTM!

Middleware initialization follows a consistent pattern with proper error handling and wrapping.


71-104: LGTM!

Controller instantiation and route setup follow a consistent pattern with proper dependency injection.

internal/bootstrap/service_bootstrap.go (3)

9-16: LGTM!

The Services struct cleanly encapsulates all service dependencies with appropriate unexported fields for internal use.


50-68: LGTM!

Docker and AccessControls service initialization follows proper dependency order with consistent error handling.


70-99: LGTM!

Auth and OAuth broker service initialization is correctly implemented with proper configuration mapping and dependency injection.

internal/bootstrap/app_bootstrap.go (4)

23-36: LGTM!

The BootstrapApp struct with nested context for runtime state is a clean approach for organizing configuration and runtime data.


44-97: LGTM!

The initialization sequence is well-organized with proper error handling and trace logging for debugging.


134-170: LGTM!

Server startup logic with unix socket support and cleanup routine initialization is correctly implemented.


172-224: LGTM!

The heartbeat implementation with proper timeout, error handling, and resource cleanup is well-structured.

Comment thread internal/bootstrap/router_bootstrap.go
Comment thread internal/bootstrap/router_bootstrap.go
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/bootstrap/app_bootstrap.go (1)

98-132: Critical: Missing assignment of configuredProviders to app.context.

The configuredProviders slice is built locally (lines 99-119) but is never assigned to app.context.configuredProviders before app.setupRouter() is called at line 128. Since router_boostrap.go line 59 reads app.context.configuredProviders, the Context controller will receive an empty/nil providers slice, breaking authentication provider display.

Apply this diff to assign the local variable to the context field:

 	if len(configuredProviders) == 0 {
 		return fmt.Errorf("no authentication providers configured")
 	}
 
+	app.context.configuredProviders = configuredProviders
+
 	// Setup router
 	engine, err := app.setupRouter()
🧹 Nitpick comments (1)
internal/bootstrap/router_boostrap.go (1)

93-98: Consider a more explicit pattern for root router access.

The &engine.RouterGroup syntax accesses the embedded RouterGroup field, which works but is somewhat unconventional. While this is valid Go and serves the purpose (Resources needs root-level routing for /resources, not /api/resources), consider using engine.Group("") for clarity.

 	resourcesController := controller.NewResourcesController(controller.ResourcesControllerConfig{
 		ResourcesDir:      app.config.ResourcesDir,
 		ResourcesDisabled: app.config.DisableResources,
-	}, &engine.RouterGroup)
+	}, engine.Group(""))
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5cad1f0 and 2932aba.

📒 Files selected for processing (2)
  • internal/bootstrap/app_bootstrap.go (6 hunks)
  • internal/bootstrap/router_boostrap.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
internal/bootstrap/router_boostrap.go (11)
internal/bootstrap/app_bootstrap.go (1)
  • BootstrapApp (23-36)
internal/middleware/context_middleware.go (2)
  • NewContextMiddleware (24-30)
  • ContextMiddlewareConfig (14-16)
internal/middleware/ui_middleware.go (1)
  • NewUIMiddleware (20-22)
internal/middleware/zerolog_middleware.go (1)
  • NewZerologMiddleware (21-23)
internal/controller/context_controller.go (3)
  • NewContextController (60-69)
  • ContextControllerConfig (44-53)
  • controller (71-75)
internal/config/config.go (3)
  • Providers (178-180)
  • CSRFCookieName (12-12)
  • RedirectCookieName (13-13)
internal/controller/oauth_controller.go (2)
  • NewOAuthController (36-43)
  • OAuthControllerConfig (21-27)
internal/controller/proxy_controller.go (2)
  • NewProxyController (31-38)
  • ProxyControllerConfig (20-22)
internal/controller/user_controller.go (2)
  • NewUserController (34-40)
  • UserControllerConfig (24-26)
internal/controller/resources_controller.go (2)
  • NewResourcesController (20-28)
  • ResourcesControllerConfig (9-12)
internal/controller/health_controller.go (2)
  • NewHealthController (9-13)
  • router (5-7)
internal/bootstrap/app_bootstrap.go (5)
internal/config/config.go (6)
  • Config (17-46)
  • User (77-81)
  • OAuthServiceConfig (57-68)
  • SessionCookieName (11-11)
  • CSRFCookieName (12-12)
  • RedirectCookieName (13-13)
internal/controller/context_controller.go (1)
  • Provider (38-42)
internal/bootstrap/service_bootstrap.go (1)
  • Services (9-16)
internal/utils/app_utils.go (2)
  • GetOAuthProvidersConfig (129-202)
  • GetCookieDomain (19-46)
internal/utils/security_utils.go (1)
  • GenerateUUID (104-107)
🔇 Additional comments (9)
internal/bootstrap/router_boostrap.go (3)

12-22: LGTM! Clean router initialization.

The router setup with recovery middleware and trusted proxies configuration is well-structured with appropriate error handling.


24-54: LGTM! Consistent middleware initialization pattern.

All three middlewares (context, UI, zerolog) follow a consistent initialization pattern with proper error handling and descriptive error messages.


12-105: Excellent refactoring! Router setup is now centralized and readable.

The extraction of router setup logic into a dedicated method improves code organization and maintainability. The consistent error handling and clear separation between middleware and controller setup makes the bootstrap flow easy to follow.

internal/bootstrap/app_bootstrap.go (6)

23-36: LGTM! Well-structured refactoring.

The introduction of the internal context struct to hold runtime state and the services field for initialized services significantly improves code organization and makes the bootstrap lifecycle clearer.


44-88: LGTM! Configuration parsing correctly updated.

All configuration values are properly parsed and assigned to app.context fields. The logging statements correctly reference the new context structure.


89-96: LGTM! Service initialization is clean and well-handled.

The centralized service initialization via app.initServices() with proper error wrapping is a good pattern.


127-169: LGTM! Clean startup sequence with proper error handling.

The router setup, background routines (DB cleanup, heartbeat), and server startup logic are well-structured. The Unix socket handling with cleanup of existing files is a good practice.


172-224: LGTM! Heartbeat improvements are solid.

The addition of a 10-second timeout to the HTTP client (lines 193-195) prevents indefinite blocking. The update to use app.context.uuid correctly adapts to the refactored structure.


226-238: LGTM! Database cleanup routine is well-implemented.

The 30-minute interval for cleaning expired sessions is reasonable, and the error handling ensures the routine continues even if individual cleanup attempts fail.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
internal/bootstrap/app_bootstrap.go (1)

89-127: Previous critical issue resolved: configuredProviders is now properly assigned.

The flow correctly:

  1. Initializes services (line 90)
  2. Builds the configuredProviders slice (lines 99-119)
  3. Assigns to app.context.configuredProviders (line 127)
  4. Calls setupRouter() (line 130)

This ensures app.context.configuredProviders is available when router_bootstrap.go creates the ContextController.

🧹 Nitpick comments (2)
internal/bootstrap/router_bootstrap.go (1)

12-22: Consider trimming whitespace when parsing trusted proxies.

If the config contains spaces after commas (e.g., "proxy1, proxy2"), the second entry would include the leading space, potentially causing proxy matching failures.

 if len(app.config.TrustedProxies) > 0 {
-    err := engine.SetTrustedProxies(strings.Split(app.config.TrustedProxies, ","))
+    proxies := strings.Split(app.config.TrustedProxies, ",")
+    for i := range proxies {
+        proxies[i] = strings.TrimSpace(proxies[i])
+    }
+    err := engine.SetTrustedProxies(proxies)
internal/bootstrap/app_bootstrap.go (1)

195-220: Good: HTTP client timeout prevents indefinite blocking.

The 10-second timeout is appropriate for analytics heartbeats. One minor improvement would be using defer for body closure to ensure cleanup even if future code changes add early returns.

 res, err := client.Do(req)

 if err != nil {
     log.Error().Err(err).Msg("Failed to send heartbeat")
     continue
 }
+defer res.Body.Close()

-res.Body.Close()

 if res.StatusCode != 200 && res.StatusCode != 201 {

Note: The current explicit Close() is correct, but defer is more resilient to future modifications.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2932aba and 7df6084.

📒 Files selected for processing (2)
  • internal/bootstrap/app_bootstrap.go (8 hunks)
  • internal/bootstrap/router_bootstrap.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
internal/bootstrap/app_bootstrap.go (5)
internal/config/config.go (6)
  • Config (17-46)
  • User (77-81)
  • OAuthServiceConfig (57-68)
  • SessionCookieName (11-11)
  • CSRFCookieName (12-12)
  • RedirectCookieName (13-13)
internal/controller/context_controller.go (1)
  • Provider (38-42)
internal/bootstrap/service_bootstrap.go (1)
  • Services (9-16)
internal/utils/app_utils.go (1)
  • GetOAuthProvidersConfig (129-202)
internal/utils/security_utils.go (1)
  • GenerateUUID (104-107)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (go)
🔇 Additional comments (4)
internal/bootstrap/router_bootstrap.go (2)

24-54: Middleware initialization follows a clean, consistent pattern.

Each middleware is instantiated, initialized with proper error handling, and attached to the engine. The error wrapping with fmt.Errorf provides good context for debugging.


56-102: Controller setup is well-structured.

The API routes are correctly grouped under /api, while the resources controller appropriately uses the root router group for static file serving. Each controller receives its required configuration and dependencies.

internal/bootstrap/app_bootstrap.go (2)

23-36: Clean refactoring of state into nested context struct.

The grouping of runtime-derived values (UUID, cookie names, providers) into app.context improves organization and clearly separates configuration from computed state. The private Services field appropriately encapsulates service dependencies.


228-240: DB cleanup routine looks correct.

The 30-minute interval for session cleanup is reasonable. The query correctly deletes sessions where the expiry timestamp is in the past.

@steveiliop56 steveiliop56 merged commit 78f97c8 into main Dec 17, 2025
8 checks passed
@Rycochet Rycochet deleted the refactor/bootstrap branch April 1, 2026 16:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants